Hướng dẫn python getattr

answer

168

getattr(object, 'x') là hoàn toàn tương đương với object.x.

chỉ có hai trường hợpgetattrcó thể hữu ích.

  • bạn không thể viết object.x, bởi vì bạn không biết trước thuộc tính nào bạn muốn (nó đến từ một chuỗi). Rất hữu ích cho lập trình meta.
  • bạn muốn cung cấp một giá trị mặc định. object.ysẽ tăng một AttributeErrornếu không có y. Nhưng getattr(object, 'y', 5)sẽ trở lại 5.

168 hữu ích 5 bình luận chia sẻ

answer

305

Các đối tượng trong Python có thể có các thuộc tính - thuộc tính dữ liệu và các hàm để làm việc với (các phương thức) đó. Trên thực tế, mọi đối tượng đều có các thuộc tính tích hợp sẵn.

Ví dụ, bạn có một đối tượng person, có một số thuộc tính: name, gendervv

Bạn truy cập vào các thuộc tính (có thể là phương pháp hay đối tượng dữ liệu) thường viết: person.name, person.gender, person.the_method()vv

Nhưng điều gì sẽ xảy ra nếu bạn không biết tên của thuộc tính tại thời điểm bạn viết chương trình? Ví dụ, bạn có tên của thuộc tính được lưu trữ trong một biến được gọi là attr_name.

nếu

attr_name = 'gender'

sau đó, thay vì viết

gender = person.gender

bạn có thể viết

gender = getattr(person, attr_name)

Một số thực hành:

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

getattrsẽ nâng lên AttributeErrornếu thuộc tính với tên đã cho không tồn tại trong đối tượng:

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

Nhưng bạn có thể chuyển một giá trị mặc định làm đối số thứ ba, giá trị này sẽ được trả về nếu thuộc tính đó không tồn tại:

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

Bạn có thể sử dụng getattrcùng với dirđể lặp lại tất cả các tên thuộc tính và nhận các giá trị của chúng:

>>> 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__  True
...
bit_length  True
...

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

Một cách sử dụng thực tế cho việc này là tìm tất cả các phương thức có tên bắt đầu bằng testvà gọi chúng .

Tương tự như getattrthere setattrcho phép bạn đặt một thuộc tính của một đối tượng có tên của nó:

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

305 hữu ích 2 bình luận chia sẻ

answer

112

Đối với tôi, getattrdễ nhất để giải thích theo cách này:

Nó cho phép bạn gọi các phương thức dựa trên nội dung của một chuỗi thay vì nhập tên phương thức.

Ví dụ, bạn không thể làm điều này:

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

bởi vì x không thuộc loại builtin, nhưng str. Tuy nhiên, bạn CÓ THỂ làm điều này:

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

Nó cho phép bạn kết nối động với các đối tượng dựa trên đầu vào của bạn. Tôi thấy nó hữu ích khi xử lý các đối tượng và mô-đun tùy chỉnh.

112 hữu ích 3 bình luận chia sẻ

answer

45

Một trường hợp sử dụng khá phổ biến getattrlà ánh xạ dữ liệu đến các hàm.

Ví dụ: trong một khung công tác web như Django hoặc Pylons, getattrgiúp dễ dàng ánh xạ URL của yêu cầu web tới chức năng sẽ xử lý nó. Ví dụ: nếu bạn xem xét phần định tuyến của Pylons, bạn sẽ thấy rằng (theo mặc định, ít nhất) nó cắt URL của một yêu cầu, như:

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

thành "khách hàng" và "danh sách". Sau đó, nó tìm kiếm một lớp điều khiển được đặt tên CustomerController. Giả sử nó tìm thấy lớp, nó tạo một thể hiện của lớp và sau đó sử dụng getattrđể lấy listphương thức của nó . Sau đó, nó gọi phương thức đó, chuyển nó yêu cầu như một đối số.

Khi bạn nắm được ý tưởng này, việc mở rộng chức năng của ứng dụng web trở nên thực sự dễ dàng: chỉ cần thêm các phương thức mới vào các lớp bộ điều khiển, sau đó tạo liên kết trong các trang của bạn sử dụng các URL thích hợp cho các phương thức đó. Tất cả điều này được thực hiện bởi getattr.

45 hữu ích 0 bình luận chia sẻ

answer

15

Dưới đây là một ví dụ nhanh và dễ hiểu về cách một lớp có thể kích hoạt các phiên bản khác nhau của phương thức lưu tùy thuộc vào hệ điều hành mà nó đang được thực thi khi sử dụng 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

Bây giờ, hãy sử dụng lớp này trong một ví dụ:

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()

15 hữu ích 0 bình luận chia sẻ

answer

8

Ngoài tất cả các câu trả lời tuyệt vời ở đây, có một cách để sử dụng getattrđể lưu các dòng mã phong phú và giữ cho nó vừa khít. Ý nghĩ này xuất hiện sau cách trình bày mã đáng sợ mà đôi khi có thể là một điều cần thiết.

Tình huống

Giả sử cấu trúc thư mục của bạn như sau:

- superheroes.py
- properties.py

Và, bạn có chức năng để nhận thông tin về Thor, Iron Man, Doctor Strangetrong superheroes.py. Bạn rất thông minh viết ra các thuộc tính của tất cả chúng properties.pytrong một tập tin nén dictvà sau đó truy cập chúng.

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'],
}

Bây giờ, giả sử bạn muốn trả lại các khả năng của từng người trong số họ theo yêu cầu trong superheroes.py. Vì vậy, có các chức năng như

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']

... và nhiều chức năng khác trả về các giá trị khác nhau dựa trên các phím và siêu anh hùng.

Với sự giúp đỡ của getattr, bạn có thể làm điều gì đó như:

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']

Bạn đã giảm đáng kể số lượng dòng mã, hàm và sự lặp lại!

Ồ và tất nhiên, nếu bạn có tên xấu như properties_of_thorcho các biến, chúng có thể được tạo và truy cập bằng cách đơn giản

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

LƯU Ý: Đối với vấn đề cụ thể này, có thể có những cách thông minh hơn để đối phó với tình huống, nhưng ý tưởng là cung cấp một cái nhìn sâu sắc về việc sử dụng getattrđúng nơi để viết mã sạch hơn.

8 hữu ích 0 bình luận chia sẻ

answer

4

# 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')

4 hữu ích 1 bình luận chia sẻ

answer

4

Đôi khi tôi sử dụng getattr(..)để khởi tạo một cách lười biếng các thuộc tính có tầm quan trọng thứ cấp ngay trước khi chúng được sử dụng trong mã.

So sánh những điều sau:

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

Về điều này:

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

Ưu điểm của cách thứ hai là n_calls_to_plotchỉ xuất hiện xung quanh vị trí trong mã nơi nó được sử dụng. Điều này rất tốt cho khả năng dễ đọc, bởi vì (1) bạn có thể thấy ngay giá trị mà nó bắt đầu bằng giá trị nào khi đọc cách nó được sử dụng, (2) nó không giới thiệu __init__(..)phương thức gây xao nhãng , lý tưởng nhất là về trạng thái khái niệm của lớp , chứ không phải là một số bộ đếm tiện ích chỉ được sử dụng bởi một trong các phương pháp của hàm vì lý do kỹ thuật, chẳng hạn như tối ưu hóa, và không liên quan gì đến ý nghĩa của đối tượng.

4 hữu ích 0 bình luận chia sẻ

answer

3

Khá thường xuyên khi tôi tạo tệp XML từ dữ liệu được lưu trữ trong một lớp, tôi thường xuyên nhận được lỗi nếu thuộc tính không tồn tại hoặc thuộc loại None. Trong trường hợp này, vấn đề của tôi là không biết tên thuộc tính là gì, như đã nêu trong câu hỏi của bạn, mà là dữ liệu đã từng được lưu trữ trong thuộc tính đó.

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

Nếu tôi đã từng hasattrlàm điều này, nó sẽ trả về Truengay cả khi giá trị thuộc tính là kiểu Nonevà điều này sẽ khiến setlệnh ElementTree của tôi không thành công.

hasattr(temp, 'hair')
>>True

Nếu giá trị thuộc tính là kiểu None, getattrcũng sẽ trả về nó, điều này khiến setlệnh ElementTree của tôi không thành công.

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

Tôi sử dụng phương pháp sau để xử lý những trường hợp này ngay bây giờ:

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

Đây là khi nào và cách tôi sử dụng getattr.

3 hữu ích 0 bình luận chia sẻ

answer

3

Một cách sử dụng khác của getattr () trong việc triển khai một câu lệnh switch trong Python. Nó sử dụng cả hai phản xạ để có được loại trường hợp.

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]))

3 hữu ích 1 bình luận chia sẻ

answer

2

setattr ()

Chúng tôi sử dụng setattr để thêm một thuộc tính vào cá thể lớp của chúng tôi. Chúng tôi chuyển thể hiện lớp, tên thuộc tính và giá trị.

getattr ()

Với getattr, chúng tôi lấy lại các giá trị này

Ví dụ

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

employee = Employee()

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

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

print(value)

2 hữu ích 0 bình luận chia sẻ

answer

2

Tôi nghĩ rằng ví dụ này là tự giải thích. Nó chạy phương thức của tham số đầu tiên, có tên được đưa ra trong tham số thứ hai.

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')()

2 hữu ích 0 bình luận chia sẻ

answer

0

Nó cũng được làm rõ từ https://www.programiz.com/python-programming/methods/built-in/getattr

class Person:
    age = 23
    name = "Adam"

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

Tuổi là: 23

Tuổi là: 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'))

Giới tính là: Nam

AttributeError: Đối tượng 'Person' không có thuộc tính 'sex'

0 hữu ích 0 bình luận chia sẻ

answer

0

Tôi đã thử bằng Python2.7.17

Một số bạn bè đã trả lời. Tuy nhiên tôi đã cố gắng gọi getattr (obj, 'set_value') và điều này không thực thi phương thức set_value, Vì vậy, tôi đã thay đổi thành getattr (obj, 'set_value') () -> Điều này giúp gọi tương tự.

Mã ví dụ:

Ví dụ 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

0 hữu ích 0 bình luận chia sẻ