Getattr () tam olarak nedir ve nasıl kullanılır?


297

Son zamanlarda fonksiyon hakkında okudumgetattr() . Sorun şu ki, kullanım fikrini hala kavrayamıyorum. Anladığım tek şeygetattr() olduğunu getattr(li, "pop")çağıran aynıdır li.pop.

Kitabın, çalışma zamanına kadar adını bilmeden bir işleve referans almak için nasıl kullandığınızdan bahsettiğini anlamadım. Belki de bu benim genel olarak programlamada bir çaylak olmak. Birisi konuya ışık tutabilir mi? Bunu tam olarak ne zaman ve nasıl kullanırım?


Hangi kısımda sorun yaşıyorsunuz? Dizeler olarak özellikler? Birinci sınıf fonksiyonlar?
Ignacio Vazquez-Abrams

1
Benim sorunum getattr () kavramını anlamak. Hala amacını anlamıyorum.
Terence Ponce

@Terence cevabım işleri daha açık hale getirmiyor mu?
Alois Cochard

@Alois, cevabın bazı şüphelerimi kesinlikle temizledi, ancak hala getattr () 'in ne için olduğunu tam olarak anlayamıyorum.
Terence Ponce

6
@ S.Lott, yaptım. Belgelerin sadece tanımı vardı, bu yüzden kullanımı hakkında kafam karıştı. Şimdi hakkında daha fazla okuduktan sonra getattr anlıyorum.
Terence Ponce

Yanıtlar:


90

getattr(object, 'x') tamamen eşdeğerdir için object.x.

Orada sadece iki olgugetattr yararlı olabilir.

  • yazamazsınız object.x, çünkü hangi özelliği istediğinizi önceden bilmiyorsunuzdur (bir dizeden gelir). Meta programlama için çok kullanışlıdır.
  • varsayılan bir değer sağlamak istiyorsunuz. hayır varsa object.yyükseltecek . Ama geri dönecek .AttributeErrorygetattr(object, 'y', 5)5

2
Bunun kabul edilen cevap olması gerektiğini hissediyorum. Çok açık ve noktaya.
yuqli

290

Python'daki nesnelerin öznitelikleri olabilir - bunlarla çalışmak için veri öznitelikleri ve işlevleri (yöntemler). Aslında, her nesnenin yerleşik öznitelikleri vardır.

Örneğin bir nesne var personçeşitli özelliklere sahiptir: name,gender vb

Bu özellik (o yöntemleri veya veri nesneleri olmak), genellikle yazma imkanına: person.name, person.gender,person.the_method() vb

Peki, programı yazarken özelliğin adını bilmiyorsanız ne olur? Örneğin, özniteliğin adı adlı bir değişkende saklanır attr_name.

Eğer

attr_name = 'gender'

o zaman yazmak yerine

gender = person.gender

Yazabilirsin

gender = getattr(person, attr_name)

Bazı uygulamalar:

Python 3.4.0 (default, Apr 11 2014, 13:05:11)

>>> class Person():
...     name = 'Victor'
...     def say(self, what):
...         print(self.name, what)
... 
>>> getattr(Person, 'name')
'Victor'
>>> attr_name = 'name'
>>> person = Person()
>>> getattr(person, attr_name)
'Victor'
>>> getattr(person, 'say')('Hello')
Victor Hello

getattrAttributeErrornesnede belirtilen ada sahip bir öznitelik yoksa yükselecektir :

>>> getattr(person, 'age')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Person' object has no attribute 'age'

Ancak, üçüncü bağımsız değişken olarak varsayılan bir değer iletebilirsiniz; bu tür bir özellik yoksa döndürülür:

>>> getattr(person, 'age', 0)
0

Tüm özellik adlarını yinelemek ve değerlerini almak için getattrbirlikte kullanabilirsiniz dir:

>>> dir(1000)
['__abs__', '__add__', ..., '__trunc__', '__xor__', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']

>>> obj = 1000
>>> for attr_name in dir(obj):
...     attr_value = getattr(obj, attr_name)
...     print(attr_name, attr_value, callable(attr_value))
... 
__abs__ <method-wrapper '__abs__' of int object at 0x7f4e927c2f90> True
...
bit_length <built-in method bit_length of int object at 0x7f4e927c2f90> True
...

>>> getattr(1000, 'bit_length')()
10

Bunun pratik bir kullanımı, isimleri ile başlayan tüm yöntemleri bulmak testve onları aramak olacaktır .

Benzer için getattrvar setattronun adını sahip bir nesnenin niteliğini belirlemek için izin veren:

>>> setattr(person, 'name', 'Andrew')
>>> person.name  # accessing instance attribute
'Andrew'
>>> Person.name  # accessing class attribute
'Victor'
>>>

9
Bana öyle geliyor ki getattr(..)2 senaryoda kullanılması gerekiyor: 1. öznitelik adı bir değişkenin içindeki bir değer getattr(person, some_attr)olduğunda (örneğin ) ve 2. varsayılan değer için üçüncü konum bağımsız değişkenini kullanmamız gerektiğinde (örn. getattr(person, 'age', 24)). getattr(person, 'age')Bana benzer bir senaryo görürsem , bunun daha çok Pythonic person.ageolduğunu düşünmeme neden olduğu gibi görünüyor person.age. Bu doğru mu?
wpcarro

102

Benim için, getattr için bu yolu açıklamak en kolay yol:

Yöntem adını, yöntem adını yazmak yerine bir dizenin içeriğine göre çağırmanıza olanak tanır.

Örneğin, bunu yapamazsınız:

obj = MyObject()
for x in ['foo', 'bar']:
    obj.x()

çünkü x türü builtindeğil str. Ancak bunu yapabilirsiniz:

obj = MyObject()
for x in ['foo', 'bar']:
    getattr(obj, x)()

Girişinize bağlı olarak nesnelere dinamik olarak bağlanmanıza izin verir. Özel nesneler ve modüller ile çalışırken faydalı buldum.


2
Bu oldukça basit ve kesin bir cevaptır.
user6037143

43

İçin oldukça yaygın bir kullanım örneği getattr , verileri işlevlerle eşlemektir.

Örneğin, Django veya Pilonlar gibi bir web çerçevesinde, getattrbir web isteğinin URL'sini, onu işleyecek işleve eşlemeyi kolaylaştırır. Örneğin, Pylonların yönlendirme başlığının altına bakarsanız, (en azından varsayılan olarak) bir isteğin URL'sini tıkladığını görürsünüz:

http://www.example.com/customers/list

"müşteriler" ve "liste" şeklinde. Sonra adlı bir denetleyici sınıfı arar CustomerController. O sınıf, daha sonra sınıfının bir örneğini oluşturur ve bulduğu varsayarsak kullanır getattralmak için onunlist yöntemini . Daha sonra bu yöntemi çağırır ve isteği argüman olarak iletir.

Bu fikri anladıktan sonra, bir web uygulamasının işlevselliğini genişletmek gerçekten çok kolay hale gelir: denetleyici sınıflarına yeni yöntemler ekleyin ve sayfalarınızda bu yöntemler için uygun URL'leri kullanan bağlantılar oluşturun. Bütün bunlar mümkün getattr.


13

Aşağıda, hangi işletim sisteminin kullanıldığına bağlı olarak bir sınıfın bir kaydetme yönteminin farklı sürümlerini nasıl tetikleyebileceğine dair hızlı ve kirli bir örnek verilmiştir getattr().

import os

class Log(object):
    def __init__(self):
        self.os = os.name
    def __getattr__(self, name):
        """ look for a 'save' attribute, or just 
          return whatever attribute was specified """
        if name == 'save':
            try:
                # try to dynamically return a save 
                # method appropriate for the user's system
                return getattr(self, self.os)
            except:
                # bail and try to return 
                # a default save method
                return getattr(self, '_save')
        else:
            return getattr(self, name)

    # each of these methods could have save logic specific to 
    # the system on which the script is executed
    def posix(self): print 'saving on a posix machine'
    def nt(self): print 'saving on an nt machine'
    def os2(self): print 'saving on an os2 machine'
    def ce(self): print 'saving on a ce machine'
    def java(self): print 'saving on a java machine'
    def riscos(self): print 'saving on a riscos machine'
    def _save(self): print 'saving on an unknown operating system'

    def which_os(self): print os.name

Şimdi bu sınıfı bir örnekte kullanalım:

logger = Log()

# Now you can do one of two things:
save_func = logger.save
# and execute it, or pass it along 
# somewhere else as 1st class:
save_func()

# or you can just call it directly:
logger.save()

# other attributes will hit the else 
# statement and still work as expected
logger.which_os()

7

Buradaki tüm şaşırtıcı cevaplar dışında, kullanmanın bir yolu var getattr bol kod satırlarını kaydetmek ve rahat tutmak için . Bu düşünce, bazen bir zorunluluk olabilen korkunç kod temsilini takiben geldi.

senaryo

Dizin yapınızın aşağıdaki gibi olduğunu varsayalım:

- superheroes.py
- properties.py

Ve, hakkında bilgi almak için işlevlere sahiptir Thor, Iron Man, Doctor Strangeiçinde superheroes.py. Hepsinin özelliklerini properties.pykompakt bir şekilde çok akıllı bir şekilde yazıyorsunuz dictve onlara erişiyorsunuz.

properties.py

thor = {
    'about': 'Asgardian god of thunder',
    'weapon': 'Mjolnir',
    'powers': ['invulnerability', 'keen senses', 'vortex breath'], # and many more
}
iron_man = {
    'about': 'A wealthy American business magnate, playboy, and ingenious scientist',
    'weapon': 'Armor',
    'powers': ['intellect', 'armor suit', 'interface with wireless connections', 'money'],
}
doctor_strange = {
    'about': ' primary protector of Earth against magical and mystical threats',
    'weapon': 'Magic',
    'powers': ['magic', 'intellect', 'martial arts'],
}

Şimdi, talep üzerine her birinin yeteneklerini iade etmek istediğinizi varsayalım superheroes.py. Yani, gibi fonksiyonlar var

from .properties import thor, iron_man, doctor_strange


def get_thor_weapon():
    return thor['weapon']


def get_iron_man_bio():
    return iron_man['about']


def get_thor_powers():
    return thor['powers']

... ve tuşlara ve süper kahramana göre farklı değerler döndüren daha fazla işlev.

Yardımıyla, getattrşöyle bir şey yapabilirsiniz:

from . import properties


def get_superhero_weapon(hero):
    superhero = getattr(properties, hero)
    return superhero['weapon']


def get_superhero_powers(hero):
    superhero = getattr(properties, hero)
    return superhero['powers']

Kod satırı, işlev ve tekrar sayısını önemli ölçüde azalttınız!

Elbette, properties_of_thordeğişkenler gibi kötü isimleriniz varsa , bunlara basitçe yaparak yapılabilir ve erişilebilir.

def get_superhero_weapon(hero):
    superhero = 'properties_of_{}'.format(hero)
    all_properties = getattr(properties, superhero)
    return all_properties['weapon']

NOT: Bu özel sorun için, durumla başa çıkmanın daha akıllı yolları olabilir, ancak fikir, getattrtemiz yerlerde kod yazmak için doğru yerlerde kullanma hakkında bir fikir vermektir .


3
# getattr

class hithere():

    def french(self):
        print 'bonjour'

    def english(self):
        print 'hello'

    def german(self):
        print 'hallo'

    def czech(self):
        print 'ahoj'

    def noidea(self):
        print 'unknown language'


def dispatch(language):
    try:
        getattr(hithere(),language)()
    except:
        getattr(hithere(),'noidea')()
        # note, do better error handling than this

dispatch('french')
dispatch('english')
dispatch('german')
dispatch('czech')
dispatch('spanish')

2
Verdiğiniz çözüm hakkında biraz daha açıklama ekleyerek cevabınızı daha ayrıntılı açıklayabilir misiniz?
abarisone

3

Bazen kullanırım getattr(..) kodda kullanılmadan hemen önce ikincil öneme sahip özellikleri tembel olarak başlatmak için kullanıyorum.

Aşağıdakileri karşılaştırın:

class Graph(object):
    def __init__(self):
        self.n_calls_to_plot = 0

    #...
    #A lot of code here
    #...

    def plot(self):
        self.n_calls_to_plot += 1

Buna:

class Graph(object):
    def plot(self):
        self.n_calls_to_plot = 1 + getattr(self, "n_calls_to_plot", 0)

İkinci yolun avantajı, n_calls_to_plotyalnızca kodda kullanılan yerin etrafında görünmesidir. Bu, okunabilirlik için iyidir, çünkü (1) nasıl kullanıldığını okurken hangi değerle başladığını hemen görebilirsiniz, (2) __init__(..)yönteme dikkat dağıtan bir şey getirmez , ideal olarak sınıfın kavramsal durumu hakkında olmalıdır , yalnızca işlevin yöntemlerinden biri tarafından optimizasyon gibi teknik nedenlerle kullanılan ve nesnenin anlamı ile ilgisi olmayan bir yardımcı program sayacı yerine.


3

Bir sınıfta depolanan verilerden bir XML dosyası oluştururken oldukça sık öznitelik yoksa veya türünde olsaydı sık sık hata alırdım None. Bu durumda, sorunum, sorunuzda belirtildiği gibi özellik adının ne olduğunu bilmiyordu, ancak daha önce bu özellikte saklanan verilerdi.

class Pet:
    def __init__(self):
        self.hair = None
        self.color = None

Ben kullandıysanız hasattrbunu yapmak, bu dönecekti Trueözellik değeri Çeşidi olsa Noneve bu benim elementtree neden olacak setkomut başarısız olmasına.

hasattr(temp, 'hair')
>>True

Öznitelik değeri türdeyse None, getattrbunu döndürür ve bu da ElementTree setkomutumun başarısız olmasına neden olur.

c = getattr(temp, 'hair')
type(c)
>> NoneType

Şu anda bu durumlarla ilgilenmek için aşağıdaki yöntemi kullanıyorum:

def getRealAttr(class_obj, class_attr, default = ''):
    temp = getattr(class_obj, class_attr, default)
    if temp is None:
        temp = default
    elif type(temp) != str:
        temp = str(temp)
    return temp

Bu ne zaman ve nasıl kullanıyorum getattr.


3

Python'da bir switch deyiminin uygulanmasında getattr () yönteminin başka bir kullanımı. Vaka türünü almak için her iki yansımayı da kullanır.

import sys

class SwitchStatement(object):
    """ a class to implement switch statement and a way to show how to use gettattr in Pythion"""

    def case_1(self):
        return "value for case_1"

    def case_2(self):
        return "value for case_2"

    def case_3(self):
        return "value for case_3"

    def case_4(self):
        return "value for case_4"

    def case_value(self, case_type=1):
        """This is the main dispatchmethod, that uses gettattr"""
        case_method = 'case_' + str(case_type)
        # fetch the relevant method name
        # Get the method from 'self'. Default to a lambda.
        method = getattr(self, case_method, lambda: "Invalid case type")
        # Call the method as we return it
        return method()

def main(_):
    switch = SwitchStatement()
    print swtich.case_value(_)

if __name__ == '__main__':
    main(int(sys.argv[1]))

Bu cevap gibi ben ama küçük yazım hatalarını düzeltmek lütfen
may

2

setattr ()

Sınıf örneğimize bir özellik eklemek için setattr kullanıyoruz . Sınıf örneğini, öznitelik adını ve değeri aktarıyoruz.

getattr ()

ile getattr bu değerleri alırız

Örneğin

Employee = type("Employee", (object,), dict())

employee = Employee()

# Set salary to 1000
setattr(employee,"salary", 1000 )

# Get the Salary
value = getattr(employee, "salary")

print(value)

1

Bence bu örnek kendini açıklayıcı. Adı ikinci parametrede verilen birinci parametre yöntemini çalıştırır.

class MyClass:
   def __init__(self):
      pass
   def MyMethod(self):
      print("Method ran")

# Create an object
object = MyClass()
# Get all the methods of a class
method_list = [func for func in dir(MyClass) if callable(getattr(MyClass, func))]
# You can use any of the methods in method_list
# "MyMethod" is the one we want to use right now

# This is the same as running "object.MyMethod()"
getattr(object,'MyMethod')()

0

Ayrıca https://www.programiz.com/python-programming/methods/built-in/getattr adresinden de açıklayıcıdır.

class Person:
    age = 23
    name = "Adam"

person = Person()
print('The age is:', getattr(person, "age"))
print('The age is:', person.age)

Yaş: 23

Yaş: 23

class Person:
    age = 23
    name = "Adam"

person = Person()

# when default value is provided
print('The sex is:', getattr(person, 'sex', 'Male'))

# when no default value is provided
print('The sex is:', getattr(person, 'sex'))

Cinsiyet: Erkek

AttributeError: 'Kişi' nesnesinin 'sex' özelliği yok


0

Python'da denedim.

Bazı arkadaşlar zaten cevap verdi. Ancak getattr (obj, 'set_value') çağırmaya çalıştım ve bu set_value yöntemini çalıştırmadı, Bu yüzden getattr (obj, 'set_value') () -> Bu aynı çağırmaya yardımcı olur.

Örnek Kod:

Örnek 1:

    class GETATT_VERIFY():
       name = "siva"
       def __init__(self):
           print "Ok"
       def set_value(self):
           self.value = "myself"
           print "oooh"
    obj = GETATT_VERIFY()
    print getattr(GETATT_VERIFY, 'name')
    getattr(obj, 'set_value')()
    print obj.value
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.