สัญลักษณ์“ at” (@) ทำอะไรใน Python


579

ฉันกำลังดูโค้ด Python บางตัวที่ใช้@สัญลักษณ์ แต่ฉันไม่รู้ว่ามันทำอะไร ฉันไม่ทราบด้วยว่าจะค้นหาสิ่งใดในการค้นหา Python docs หรือ Google จะไม่แสดงผลลัพธ์ที่เกี่ยวข้องเมื่อ@มีการรวมสัญลักษณ์

คำตอบ:


303

@สัญลักษณ์ที่จุดเริ่มต้นของเส้นที่ใช้สำหรับการเรียนการทำงานและวิธีการตกแต่ง

อ่านเพิ่มเติมได้ที่นี่:

PEP 318: นักตกแต่ง

Python Decorators

เครื่องมือตกแต่ง Python ที่คุณใช้บ่อยที่สุดคือ:

@property

@classmethod

@staticmethod

ถ้าคุณเห็น@เส้นกึ่งกลางของเส้นนั่นก็คือการคูณเมทริกซ์ที่แตกต่างกัน เลื่อนลงไปดูคำตอบอื่น ๆ @ที่อยู่ที่การใช้งานของ


31
ดูเหมือนว่ามันยังสามารถเป็นตัวดำเนินการคูณเมทริกซ์ได้เช่นกัน: stackoverflow.com/a/21563036/5049813
Pro Q

@decorators สามารถเพิ่มได้ด้วย
Vijay Panchal

347

ตัวอย่าง

class Pizza(object):
    def __init__(self):
        self.toppings = []

    def __call__(self, topping):
        # When using '@instance_of_pizza' before a function definition
        # the function gets passed onto 'topping'.
        self.toppings.append(topping())

    def __repr__(self):
        return str(self.toppings)

pizza = Pizza()

@pizza
def cheese():
    return 'cheese'
@pizza
def sauce():
    return 'sauce'

print pizza
# ['cheese', 'sauce']

นี่แสดงให้เห็นว่าfunction/ method/ classคุณกำลังกำหนดหลังจากมัณฑนากรเพียงแค่ส่งต่อargumentไปยังfunction/ ถึงmethodทันทีหลังจากที่@ลงชื่อเข้าใช้

การพบเห็นครั้งแรก

การออกแบบ microframework Flaskเริ่มจากนักตกแต่งในรูปแบบต่อไปนี้

from flask import Flask
app = Flask(__name__)

@app.route("/")
def hello():
    return "Hello World!"

สิ่งนี้จะแปลเป็น:

rule      = "/"
view_func = hello
# They go as arguments here in 'flask/app.py'
def add_url_rule(self, rule, endpoint=None, view_func=None, **options):
    pass

การตระหนักถึงสิ่งนี้ในที่สุดก็ทำให้ฉันรู้สึกสงบสุขกับ Flask


7
ในกรณีของ Flasks app.route("/"): ฟังก์ชั่นนี้จะส่งคืนฟังก์ชันซึ่งคุณเรียกใช้ด้วยhello()อาร์กิวเมนต์ของคุณ
shaqed

3
อะไรคือข้อดีของการตกแต่งภายในหรือการใช้ประโยชน์จากซินแทคติคแทนที่จะเป็น (เช่น) เพียงแค่เรียกอะไรบางอย่างapp.route("/", hello)ทันทีหลังจากกำหนดhelloหรือแม้แต่กำหนดhelloเป็นแลมบ์ดาในการโต้แย้งapp.route? (ตัวอย่างหลังเป็นเรื่องธรรมดากับhttp.Serverเส้นทางNode.js และเส้นทางด่วน)
iono

185

ข้อมูลโค้ดนี้:

def decorator(func):
   return func

@decorator
def some_func():
    pass

เทียบเท่ากับรหัสนี้:

def decorator(func):
    return func

def some_func():
    pass

some_func = decorator(some_func)

ในคำจำกัดความของมัณฑนากรคุณสามารถเพิ่มบางสิ่งที่ปรับเปลี่ยนซึ่งจะไม่ถูกส่งกลับโดยฟังก์ชัน


1
ในบรรทัดนี้ของ "ome_func = decorator (some_func)" some_func ตัวแรกคือตัวแปร = ไปยังฟังก์ชัน some_func ใช่ไหม?
Viragos

147

ใน Python 3.5 คุณสามารถโอเวอร์โหลด@ในฐานะผู้ดำเนินการ มันถูกตั้งชื่อเป็น__matmul__เพราะมันถูกออกแบบมาเพื่อทำการคูณเมทริกซ์ แต่มันสามารถเป็นอะไรก็ได้ที่คุณต้องการ ดูรายละเอียดPEP465

นี่เป็นการใช้งานการคูณเมทริกซ์อย่างง่าย

class Mat(list):
    def __matmul__(self, B):
        A = self
        return Mat([[sum(A[i][k]*B[k][j] for k in range(len(B)))
                    for j in range(len(B[0])) ] for i in range(len(A))])

A = Mat([[1,3],[7,5]])
B = Mat([[6,8],[4,2]])

print(A @ B)

รหัสนี้ให้ผล:

[[18, 14], [62, 66]]

14
นอกจากนี้คุณยังมี@=(ในสถานที่) __imatmul__ผู้ประกอบการซึ่งเป็น
Pål GD

มีผู้ประกอบการ overridable อื่น ๆ เช่นนี้? ฉันรู้__add__และ__sub__เชื่อมโยงกับ + และ - ตามลำดับ แต่ไม่เคยได้ยิน@เครื่องหมายใดมาก่อน มีคนอื่นบ้างไหมที่ซุ่มซ่อนอยู่ที่นั่น?
โทมัสคิมเบอร์

103

สัญลักษณ์“ at” (@) ทำอะไรใน Python

กล่าวโดยย่อคือมันใช้ในไวยากรณ์มัณฑนากรและการคูณเมทริกซ์

ในบริบทของการตกแต่งไวยากรณ์นี้:

@decorator
def decorated_function():
    """this function is decorated"""

เทียบเท่ากับสิ่งนี้:

def decorated_function():
    """this function is decorated"""

decorated_function = decorator(decorated_function)

ในบริบทของการคูณเมทริกซ์a @ bเรียกใช้a.__matmul__(b)- สร้างไวยากรณ์นี้:

a @ b

เทียบเท่ากับ

dot(a, b)

และ

a @= b

เทียบเท่ากับ

a = dot(a, b)

โดยที่dotตัวอย่างฟังก์ชันการคูณเมทริกซ์ numpy และaและbเป็นเมทริกซ์

คุณจะค้นพบสิ่งนี้ด้วยตัวเองได้อย่างไร?

ฉันไม่ทราบด้วยว่าจะค้นหาสิ่งใดในการค้นหา Python docs หรือ Google จะไม่แสดงผลลัพธ์ที่เกี่ยวข้องเมื่อมีสัญลักษณ์ @ รวมอยู่ด้วย

หากคุณต้องการมีมุมมองที่ค่อนข้างสมบูรณ์เกี่ยวกับสิ่งที่ไวยากรณ์ของส่วนใดของ python ให้ดูที่ไฟล์ไวยากรณ์โดยตรง สำหรับสาขา Python 3:

~$ grep -C 1 "@" cpython/Grammar/Grammar 

decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
decorators: decorator+
--
testlist_star_expr: (test|star_expr) (',' (test|star_expr))* [',']
augassign: ('+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' | '^=' |
            '<<=' | '>>=' | '**=' | '//=')
--
arith_expr: term (('+'|'-') term)*
term: factor (('*'|'@'|'/'|'%'|'//') factor)*
factor: ('+'|'-'|'~') factor | power

เราสามารถดูที่นี่ที่@ใช้ในสามบริบท:

  • ตกแต่ง
  • ตัวดำเนินการระหว่างปัจจัย
  • ผู้ประกอบการที่ได้รับมอบหมายเพิ่มเติม

ไวยากรณ์มัณฑนากร:

การค้นหา google สำหรับ "decorator python docs" เป็นหนึ่งในผลลัพธ์อันดับต้น ๆ ส่วน "คำสั่งผสม" ของ "Python Language Reference" เลื่อนลงไปยังส่วนที่เกี่ยวกับคำจำกัดความของฟังก์ชั่นซึ่งเราสามารถค้นหาได้โดยการค้นหาคำว่า "มัณฑนากร" เราจะเห็นว่า ... มีอะไรให้อ่านมากมาย แต่คำว่า"มัณฑนากร" เป็นลิงค์ไปยังอภิธานศัพท์ซึ่งบอกเราว่า:

มัณฑนากร

ฟังก์ชั่นกลับมาฟังก์ชั่นอื่นมักจะใช้เป็นการแปลงฟังก์ชั่นโดยใช้@wrapperไวยากรณ์ ตัวอย่างทั่วไปสำหรับตกแต่งเป็นและclassmethod()staticmethod()

ไวยากรณ์มัณฑนากรเป็นเพียงน้ำตาลเชิงประโยคเพียงสองคำจำกัดความฟังก์ชันต่อไปนี้เทียบเท่ากับ semantically:

def f(...):
    ...
f = staticmethod(f)

@staticmethod
def f(...):
    ...

มีแนวคิดเดียวกันสำหรับคลาส แต่มีการใช้งานน้อยกว่าปกติ ดูเอกสารประกอบสำหรับคำนิยามฟังก์ชั่นและคำจำกัดความของชั้นเรียนสำหรับข้อมูลเพิ่มเติมเกี่ยวกับการตกแต่ง

ดังนั้นเราจะเห็นว่า

@foo
def bar():
    pass

มีความหมายเหมือนกับ:

def bar():
    pass

bar = foo(bar)

พวกเขาจะไม่เหมือนกันเพราะ Python ประเมินการแสดงออก foo (ซึ่งอาจเป็นการค้นหาประและฟังก์ชั่นการโทร) ก่อนที่แถบด้วย@ไวยากรณ์มัณฑนากร ( ) แต่ประเมินการแสดงออกของ foo หลังจากบาร์ในกรณีอื่น ๆ

(หากความแตกต่างนี้สร้างความแตกต่างในความหมายของรหัสของคุณคุณควรพิจารณาสิ่งที่คุณทำกับชีวิตของคุณเพราะมันจะเป็นพยาธิวิทยา)

ตกแต่งซ้อนกัน

ถ้าเรากลับไปที่เอกสารไวยากรณ์ของนิยามฟังก์ชันเราจะเห็น:

@f1(arg)
@f2
def func(): pass

เทียบเท่ากับ

def func(): pass
func = f1(arg)(f2(func))

นี่คือการสาธิตที่เราสามารถเรียกใช้ฟังก์ชันที่เป็นมัณฑนากรก่อนเช่นเดียวกับผู้ตกแต่งสแต็ค ฟังก์ชั่นใน Python เป็นวัตถุชั้นหนึ่ง - ซึ่งหมายความว่าคุณสามารถส่งผ่านฟังก์ชั่นเป็นข้อโต้แย้งไปยังฟังก์ชั่นอื่นและกลับมาฟังก์ชั่น ผู้ตกแต่งทำสิ่งเหล่านี้ทั้งสอง

ถ้าเราสแต็คตกแต่งภายในฟังก์ชันตามที่กำหนดไว้จะถูกส่งผ่านไปยังมัณฑนากรก่อนจากนั้นต่อไปเรื่อย ๆ

นั่นคือผลรวมการใช้@ในบริบทของนักตกแต่ง

ผู้ประกอบการ @

ในส่วนการวิเคราะห์คำศัพท์ของการอ้างอิงภาษาเรามีส่วนที่เกี่ยวกับตัวดำเนินการซึ่งรวมถึง@ซึ่งทำให้มันเป็นตัวดำเนินการด้วย:

โทเค็นต่อไปนี้เป็นโอเปอเรเตอร์:

+       -       *       **      /       //      %      @
<<      >>      &       |       ^       ~
<       >       <=      >=      ==      !=

และในหน้าถัดไปรูปแบบข้อมูลที่เรามีส่วนประเภทการลอกเลียนแบบตัวเลข ,

object.__add__(self, other)
object.__sub__(self, other) 
object.__mul__(self, other) 
object.__matmul__(self, other) 
object.__truediv__(self, other) 
object.__floordiv__(self, other)

[... ] วิธีการเหล่านี้ถูกเรียกให้ใช้การดำเนินการทางเลขฐานสอง (+ , -, *, @, /, //[ ... ]

และเราเห็นว่า __matmul__@สอดคล้องกับ หากเราค้นหาเอกสารสำหรับ "matmul" เราจะได้รับลิงค์ไปยังมีอะไรใหม่ใน Python 3.5ด้วย "matmul" ภายใต้หัวข้อ "PEP 465 - ตัวดำเนินการมัดเฉพาะสำหรับการคูณเมทริกซ์"

จะสามารถดำเนินการโดยการกำหนด__matmul__(), __rmatmul__()และ __imatmul__()ปกติสะท้อนให้เห็นและในสถานที่คูณเมทริกซ์

(ตอนนี้เราเรียนรู้ว่า@=เป็นรุ่นในสถานที่) มันอธิบายเพิ่มเติม:

การคูณเมทริกซ์เป็นการดำเนินการที่พบได้ทั่วไปในหลายสาขาของคณิตศาสตร์วิทยาศาสตร์วิศวกรรมและการเพิ่ม @ อนุญาตให้เขียนโค้ดที่สะอาดกว่า:

S = (H @ beta - r).T @ inv(H @ V @ H.T) @ (H @ beta - r)

แทน:

S = dot((dot(H, beta) - r).T,
        dot(inv(dot(dot(H, V), H.T)), dot(H, beta) - r))

ในขณะที่โอเปอเรเตอร์สามารถโอเวอร์โหลดเพื่อทำเกือบทุกอย่างในnumpyตัวอย่างเช่นเราจะใช้ไวยากรณ์นี้เพื่อคำนวณผลิตภัณฑ์ภายในและภายนอกของอาร์เรย์และเมทริกซ์:

>>> from numpy import array, matrix
>>> array([[1,2,3]]).T @ array([[1,2,3]])
array([[1, 2, 3],
       [2, 4, 6],
       [3, 6, 9]])
>>> array([[1,2,3]]) @ array([[1,2,3]]).T
array([[14]])
>>> matrix([1,2,3]).T @ matrix([1,2,3])
matrix([[1, 2, 3],
        [2, 4, 6],
        [3, 6, 9]])
>>> matrix([1,2,3]) @ matrix([1,2,3]).T
matrix([[14]])

การคูณเมทริกซ์ Inplace: @=

ขณะทำการค้นคว้าการใช้งานก่อนหน้านี้เราได้เรียนรู้ว่ายังมีการคูณเมทริกซ์แบบ inplace หากเราพยายามใช้งานเราอาจพบว่ายังไม่ได้ใช้งานสำหรับผู้ใช้จำนวนมาก:

>>> m = matrix([1,2,3])
>>> m @= m.T
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: In-place matrix multiplication is not (yet) supported. Use 'a = a @ b' instead of 'a @= b'.

เมื่อมีการใช้งานฉันคาดว่าผลลัพธ์จะเป็นดังนี้:

>>> m = matrix([1,2,3])
>>> m @= m.T
>>> m
matrix([[14]])

36

สัญลักษณ์“ at” (@) ทำอะไรใน Python

สัญลักษณ์ @ เป็นงูหลาม syntactic น้ำตาลให้ใช้decoratorใน
การถอดความคำถามมันเกี่ยวกับสิ่งที่ช่างตกแต่งทำในงูหลามอะไร?

ใส่ง่ายdecoratorช่วยให้คุณสามารถแก้ไขคำจำกัดความของฟังก์ชั่นที่กำหนดได้โดยไม่ต้องสัมผัสส่วนในสุด (ปิด)
เป็นกรณีส่วนใหญ่เมื่อคุณนำเข้าแพ็คเกจที่ยอดเยี่ยมจากบุคคลที่สาม คุณสามารถมองเห็นมันคุณสามารถใช้งานได้ แต่คุณไม่สามารถสัมผัสภายในและหัวใจของมัน

นี่คือตัวอย่างด่วน
สมมติว่าฉันกำหนดread_a_bookฟังก์ชันบน Ipython

In [9]: def read_a_book():
   ...:     return "I am reading the book: "
   ...: 
In [10]: read_a_book()
Out[10]: 'I am reading the book: '

คุณเห็นฉันลืมที่จะเพิ่มชื่อมัน
วิธีแก้ปัญหาดังกล่าว? แน่นอนฉันสามารถกำหนดฟังก์ชั่นใหม่เป็น:

def read_a_book():
    return "I am reading the book: 'Python Cookbook'"

อย่างไรก็ตามจะเกิดอะไรขึ้นถ้าฉันไม่ได้รับอนุญาตให้จัดการฟังก์ชั่นดั้งเดิมหรือหากมีฟังก์ชั่นดังกล่าวนับพันที่ต้องจัดการ

แก้ไขปัญหาด้วยการคิดต่าง ๆ และกำหนด new_function

def add_a_book(func):
    def wrapper():
        return func() + "Python Cookbook"
    return wrapper

จากนั้นจ้างมัน

In [14]: read_a_book = add_a_book(read_a_book)
In [15]: read_a_book()
Out[15]: 'I am reading the book: Python Cookbook'

คุณเห็นไหมว่า Tada ฉันแก้ไขread_a_bookโดยไม่แตะต้องมัน decoratorไม่มีอะไรหยุดฉันพร้อมกับ

เกี่ยวกับอะไร @

@add_a_book
def read_a_book():
    return "I am reading the book: "
In [17]: read_a_book()
Out[17]: 'I am reading the book: Python Cookbook'

@add_a_bookเป็นวิธีแฟนซีและสะดวกในการพูดread_a_book = add_a_book(read_a_book)มันเป็นน้ำตาล syntactic ไม่มีอะไรที่นักเล่นเพิ่มเติมเกี่ยวกับมัน


16

ถ้าคุณจะหมายถึงรหัสบางอย่างในโน๊ตบุ๊คหลามซึ่งมีการใช้Numpyห้องสมุดแล้ว@ operatorหมายถึงการคูณเมทริกซ์ ตัวอย่างเช่น:

import numpy as np
def forward(xi, W1, b1, W2, b2):
    z1 = W1 @ xi + b1
    a1 = sigma(z1)
    z2 = W2 @ a1 + b2
    return z2, a1


6

มีการเพิ่มผู้ตกแต่งใน Python เพื่อให้การทำงานและวิธีการห่อ (ฟังก์ชั่นที่ได้รับฟังก์ชั่นและส่งกลับหนึ่งปรับปรุง) ง่ายต่อการอ่านและเข้าใจ กรณีการใช้งานดั้งเดิมจะสามารถกำหนดวิธีการเป็นวิธีการเรียนหรือวิธีการคงที่บนหัวของคำนิยามของพวกเขา หากไม่มีไวยากรณ์มัณฑนากรมันจะต้องมีคำจำกัดความค่อนข้างเบาบางและซ้ำ ๆ :

class WithoutDecorators:
def some_static_method():
    print("this is static method")
some_static_method = staticmethod(some_static_method)

def some_class_method(cls):
    print("this is class method")
some_class_method = classmethod(some_class_method)

หากมีการใช้ไวยากรณ์ของมัณฑนากรเพื่อจุดประสงค์เดียวกันรหัสจะสั้นและง่ายต่อการเข้าใจ:

class WithDecorators:
    @staticmethod
    def some_static_method():
        print("this is static method")

    @classmethod
    def some_class_method(cls):
        print("this is class method")

ไวยากรณ์ทั่วไปและการใช้งานที่เป็นไปได้

มัณฑนากรโดยทั่วไปเป็นวัตถุที่มีชื่อ ( ไม่อนุญาตให้ใช้นิพจน์แลมบ์ดา ) ที่รับอาร์กิวเมนต์เดี่ยวเมื่อถูกเรียก (มันจะเป็นฟังก์ชั่นการตกแต่ง) และส่งกลับวัตถุที่เรียกได้อีกอันหนึ่ง "Callable" ใช้ที่นี่แทน "function" พร้อมการไตร่ตรองล่วงหน้า ในขณะที่นักตกแต่งมักจะกล่าวถึงในขอบเขตของวิธีการและฟังก์ชั่นพวกเขาจะไม่ จำกัด เพียงพวกเขา ในความเป็นจริงสิ่งใดที่เรียกได้ (วัตถุใด ๆ ที่ใช้วิธี _call__ นั้นถือว่าเรียกได้ว่า) สามารถใช้เป็นมัณฑนากรและบ่อยครั้งที่วัตถุที่ส่งคืนโดยพวกเขาไม่ใช่ฟังก์ชั่นที่ง่าย แต่อินสแตนซ์เพิ่มเติม

ไวยากรณ์มัณฑนากรเป็นเพียงเฉพาะน้ำตาลประโยค พิจารณาการใช้มัณฑนากรต่อไปนี้:

@some_decorator
def decorated_function():
    pass

สิ่งนี้สามารถถูกแทนที่ด้วยการเรียกมัณฑนากรอย่างชัดเจนและการกำหนดฟังก์ชันใหม่:

def decorated_function():
    pass
decorated_function = some_decorator(decorated_function)

อย่างไรก็ตามหลังสามารถอ่านได้น้อยและยากที่จะเข้าใจหากมีการใช้เครื่องมือตกแต่งหลายอย่างในฟังก์ชั่นเดียว มัณฑนากรสามารถใช้งานได้หลายวิธีดังแสดงด้านล่าง:

เป็นฟังก์ชั่น

มีหลายวิธีในการเขียนผู้ตกแต่งที่กำหนดเอง แต่วิธีที่ง่ายที่สุดคือการเขียนฟังก์ชั่นที่คืนค่าฟังก์ชันย่อยที่ตัดการเรียกใช้ฟังก์ชันดั้งเดิม

รูปแบบทั่วไปมีดังนี้:

def mydecorator(function):
    def wrapped(*args, **kwargs):
        # do some stuff before the original
        # function gets called
        result = function(*args, **kwargs)
        # do some stuff after function call and
        # return the result
        return result
    # return wrapper as a decorated function
    return wrapped

เป็นคลาส

ในขณะที่มัณฑนากรเกือบทุกคนสามารถนำมาใช้โดยใช้ฟังก์ชั่นมีบางสถานการณ์เมื่อใช้คลาสที่ผู้ใช้กำหนดเองเป็นตัวเลือกที่ดีกว่า เรื่องนี้มักจะเกิดขึ้นจริงเมื่อมัณฑนากรต้องการ parametrization ที่ซับซ้อนหรือขึ้นอยู่กับสถานะที่เฉพาะเจาะจง

รูปแบบทั่วไปสำหรับมัณฑนากร nonparametrized เป็นคลาสมีดังต่อไปนี้:

class DecoratorAsClass:
    def __init__(self, function):
        self.function = function

    def __call__(self, *args, **kwargs):
        # do some stuff before the original
        # function gets called
        result = self.function(*args, **kwargs)
        # do some stuff after function call and
        # return the result
        return result

นักออกแบบตกแต่งภายใน

ในรหัสจริงมักจะมีความต้องการที่จะใช้การตกแต่งที่สามารถ parametrized เมื่อใช้ฟังก์ชั่นเป็นมัณฑนากรแล้ววิธีการแก้ก็ง่าย - ต้องใช้การห่อในระดับที่สอง นี่คือตัวอย่างง่ายๆของมัณฑนากรที่ทำหน้าที่เรียกใช้ฟังก์ชั่นการตกแต่งซ้ำตามจำนวนครั้งที่ระบุทุกครั้งที่เรียกใช้:

def repeat(number=3):
"""Cause decorated function to be repeated a number of times.

Last value of original function call is returned as a result
:param number: number of repetitions, 3 if not specified
"""
def actual_decorator(function):
    def wrapper(*args, **kwargs):
        result = None
        for _ in range(number):
            result = function(*args, **kwargs)
        return result
    return wrapper
return actual_decorator

มัณฑนากรที่กำหนดด้วยวิธีนี้สามารถยอมรับพารามิเตอร์:

>>> @repeat(2)
... def foo():
...     print("foo")
...
>>> foo()
foo
foo

โปรดทราบว่าแม้ว่ามัณฑนากร parametrized มีค่าเริ่มต้นสำหรับอาร์กิวเมนต์อาร์กิวเมนต์จะต้องอยู่ในวงเล็บหลังชื่อ วิธีที่ถูกต้องในการใช้มัณฑนากรก่อนหน้านี้ที่มีอาร์กิวเมนต์เริ่มต้นมีดังนี้:

>>> @repeat()
... def bar():
...     print("bar")
...
>>> bar()
bar
bar
bar

ในที่สุดให้ดูการตกแต่งด้วยคุณสมบัติ

คุณสมบัติ

คุณสมบัติจัดเตรียมชนิดdescriptorในตัวที่รู้วิธีเชื่อมโยงแอ็ตทริบิวต์กับชุดของเมธอด พร็อพเพอร์ตี้มีอาร์กิวเมนต์ที่เป็นทางเลือกสี่แบบ: fget, fset, fdel และ doc คนสุดท้ายที่สามารถให้เพื่อกำหนด docstring ที่เชื่อมโยงกับคุณลักษณะราวกับว่ามันเป็นวิธีการ นี่คือตัวอย่างของคลาสสี่เหลี่ยมผืนผ้าที่สามารถควบคุมได้โดยการเข้าถึงคุณสมบัติที่เก็บจุดสองมุมโดยตรงหรือโดยใช้คุณสมบัติความกว้างและความสูง:

class Rectangle:
    def __init__(self, x1, y1, x2, y2):
        self.x1, self.y1 = x1, y1
        self.x2, self.y2 = x2, y2

    def _width_get(self):
        return self.x2 - self.x1

    def _width_set(self, value):
        self.x2 = self.x1 + value

    def _height_get(self):
        return self.y2 - self.y1

    def _height_set(self, value):
        self.y2 = self.y1 + value

    width = property(
        _width_get, _width_set,
        doc="rectangle width measured from left"
    )
    height = property(
        _height_get, _height_set,
        doc="rectangle height measured from top"
    )

    def __repr__(self):
        return "{}({}, {}, {}, {})".format(
            self.__class__.__name__,
            self.x1, self.y1, self.x2, self.y2
    )

ไวยากรณ์ที่ดีที่สุดสำหรับการสร้างคุณสมบัติใช้คุณสมบัติเป็นมัณฑนากร สิ่งนี้จะลดจำนวนลายเซ็นของเมธอดภายในคลาสและทำให้โค้ดอ่านได้ง่ายขึ้นและบำรุงรักษาได้ ด้วยการตกแต่งระดับดังกล่าวจะกลายเป็น:

class Rectangle:
    def __init__(self, x1, y1, x2, y2):
        self.x1, self.y1 = x1, y1
        self.x2, self.y2 = x2, y2

    @property
    def width(self):
        """rectangle height measured from top"""
        return self.x2 - self.x1

    @width.setter
    def width(self, value):
        self.x2 = self.x1 + value

    @property
    def height(self):
        """rectangle height measured from top"""
        return self.y2 - self.y1

    @height.setter
    def height(self, value):
        self.y2 = self.y1 + value

2

ที่จะพูดในสิ่งที่คนอื่นมีในวิธีที่แตกต่าง: ใช่มันเป็นมัณฑนากร

ใน Python มันเหมือนกับ:

  1. การสร้างฟังก์ชั่น (ตามด้วยการโทร @)
  2. การเรียกฟังก์ชันอื่นเพื่อใช้งานฟังก์ชันที่คุณสร้างขึ้น ส่งคืนฟังก์ชันใหม่ ฟังก์ชันที่คุณเรียกใช้เป็นอาร์กิวเมนต์ของ @
  3. แทนที่ฟังก์ชั่นที่กำหนดด้วยฟังก์ชั่นใหม่กลับมา

สิ่งนี้สามารถใช้กับสิ่งที่มีประโยชน์ได้ทุกประเภททำไปได้เพราะฟังก์ชั่นเป็นวัตถุและเพียงแค่ต้องการคำแนะนำ


2

สัญลักษณ์ @ ยังใช้เพื่อการเข้าถึงตัวแปรภายใน plydata / หมีแพนด้า dataframe pandas.DataFrame.queryแบบสอบถาม ตัวอย่าง:

df = pandas.DataFrame({'foo': [1,2,15,17]})
y = 10
df >> query('foo > @y') # plydata
df.query('foo > @y') # pandas

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.